package math;

import static math.ExpressionBuilder.not;
import static math.ExpressionBuilder.and;
import static math.ExpressionBuilder.or;

public class Xor implements BooleanExpression {

  private BooleanExpression arg2;
  
  private BooleanExpression arg1;
  
  private Xor(BooleanExpression arg1, BooleanExpression arg2){
    this.arg1 = arg1;
    this.arg2 = arg2;
  }
  
  public static BooleanExpression createXor(BooleanExpression arg1, BooleanExpression arg2){
    return new Xor(arg1, arg2);
  }
  
  @Override
  public <R> R accept(ExpressionVisitor<R> visitor) {
    return visitor.visitXor(this);
  }

  @Override
  public int countMembers() {
    return 1 + arg1.countMembers() + arg2.countMembers();
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Xor) {
      Xor xor2 = (Xor) obj;
      return xor2.arg1.equals(arg1) && xor2.arg2.equals(arg2);
    } else
      return false;
  }
  
  @Override
  public boolean matches(Expression expr) {
    if (expr instanceof Xor) {
      Xor eXor = (Xor) expr;
      return arg1.matches(eXor.getArg1()) && arg2.matches(eXor.getArg2());
    } else
      return false;
  }

  public BooleanExpression getArg1() {
    return arg1;
  }
  
  public BooleanExpression getArg2() {
    return arg2;
  }
  
  @Override
  public int hashCode() {
    return arg1.hashCode() ^ (arg2.hashCode() * 78648);
  }

  @Override
  public Expression simplify() {
    return this;
  }

  @Override
  public String toString() {
    return '(' + arg1.toString() + " xor " + arg2.toString() + ")";
  }

  @Override
  public BooleanExpression toDNF() {
    return or(and(arg1, not(arg2)), and(not(arg1), arg2)).toDNF();
  }
}